package com.example.demo.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.example.demo.config.QRCodeConstant;
import com.example.demo.dao.TAssistLevelMapper;
import com.example.demo.dao.TFollowInfoMapper;
import com.example.demo.dao.TUserMapper;
import com.example.demo.message.*;
import com.example.demo.model.*;
import com.example.demo.service.WxService;
import com.example.demo.token.TokenUtils;
import com.example.demo.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 马拉圈
 * Date: 2023-10-22
 * Time: 12:16
 */
@Service
public class WxServiceImpl implements WxService {

    // 注入token
    @Value("${wx.token}")
    private String token;

    @Value("${redirect.domain}")
    private String redirectDomain;

    @Value("${wx.appid}")
    private String appId;

    @Value("${wx.secret}")
    private String secret;

    @Autowired
    private TUserMapper userMapper;

    @Autowired
    private TFollowInfoMapper followInfoMapper;

    @Autowired
    private TAssistLevelMapper assistLevelMapper;


    /**
     *  检查是否是微信服务器发来的请求
     * @param signature
     * @param timestamp
     * @param nonce
     * @param echostr
     * @return 非回显字符串的其他都视为不通过
     */

    @Override
    public String check(String signature, String timestamp, String nonce, String echostr) {
        String[] list = {token, timestamp, nonce};
        Arrays.sort(list);
        // 2) 将三个字符串以此顺序进行拼接
        StringBuilder builder = new StringBuilder();
        for(String s : list) {
            builder.append(s);
        }
        // 2.1) 加密
        try {
            MessageDigest messageDigest = MessageDigest.getInstance("sha1");
            byte[] digest = messageDigest.digest(builder.toString().getBytes(StandardCharsets.UTF_8));
            // 2.2) 将加密后的byte数组转换为signature一样的格式（每个字节都转换为十六进制进行拼接）
            builder = new StringBuilder();
            for(byte b : digest) {
                // builder.append(Integer.toHexString(b));不能这么弄因为这样弄b如果是负，那么就凉凉
                // 这样写保证两位十六进制都存在并且正确
                builder.append(Integer.toHexString((b >> 4) & 15));//前四个字节转换为十六进制
                builder.append(Integer.toHexString(b & 15));//后四个字节转换为十六进制
            }
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException(e);
        }
        // 3) 核对请求是否来自于微信（加密解析后的字符串与signature比较）
        if(builder.toString().equals(signature)) {
            // 相同才返回回显字符串
            // 并且返回echostr代表开发者确认了这是公众号服务器发来的请求，公众号就进行配置
            return echostr;
        } else {
            // 否则返回null
            return null;
        }
    }

    /**
     * 处理消息，制作返回信息
     * @param map 消息参数
     * @return xml数据
     */
    @Override
    public String handleMessage(Map<String, Object> map) {
        String message = "";
        String MsgType = (String) map.get("MsgType");
        switch (MsgType) {
            case "event":
                message = handleEvent(map);//处理事件
                break;
            case "text":
                message = handleText(map);//处理文本
                break;
            case "image":
                message = handleImage(map);//处理图片
                break;
            default:
                System.out.println("其他消息类型");
                break;
        }
//        System.out.println(message);
        return message;
    }

    @Override
    public String getSignUpUserInfo(String code) {
        //根据code获取Access_token的地址
        String url = "https://api.weixin.qq.com/sns/oauth2/access_token" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
            this.put("appid", appId);
            this.put("secret", secret);
            this.put("code", code);
            this.put("grant_type", "authorization_code");
        }});
        // 发送请求，接受响应，解析响应
        String result = HttpUtils.doGet(url);
        System.out.println(result);
//        String accessToken = (String) JsonUtils.jsonToMap(url).get("access_token");
//        String openId = (String) JsonUtils.jsonToMap(url).get("access_token");
        String accessToken = JSONObject.parseObject(result).getString("access_token");
        String openId = JSONObject.parseObject(result).getString("access_token");
        String userInfoUrl = "https://api.weixin.qq.com/sns/userinfo" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
            this.put("access_token", accessToken);
            this.put("openid", openId);
            this.put("lang", "zh_CN");
        }});
        //拉取用户信息
        String userInfo = HttpUtils.doGet(userInfoUrl);
        // 解析
//        SubscribedUser user = JsonUtils.jsonToObject(userInfo, SubscribedUser.class);
        SubscribedUser user = JSONObject.parseObject(userInfo, SubscribedUser.class);
        // 存入微信号昵称对应表
        TUser tUser = BeanCopyUtils.copyBean(user, TUser.class);
        userMapper.insertSelective(tUser);
        String html = HtmlUtils.getSignUpHtml();
        return html;
    }

    @Override
    public String getRankingList() {
        List<RankingItem> rankingList = followInfoMapper.selectRankingList();
        String html = HtmlUtils.createHtml(rankingList);
        return html;
    }

    private String handleImage(Map<String, Object> map) {
        String picUrl = (String) map.get("PicUrl");
        String content = ImageUtils.getImageText(picUrl);
        map.put("Content", content);
        TextMessage textMessage = TextMessage.getReplyTextMessage(map);
        String message = XmlUtils.objectToXml(textMessage);
        return message;
    }

    private String handleText(Map<String, Object> map) {
        String message = "";
        String content = (String) map.get("Content");
        if(!StringUtils.hasLength(content)) {
            return "";
        }
        switch (content) {
            case "图文":
                NewsMessage newsMessage = NewsMessage.getReplyNewsMessage(map);
                message = XmlUtils.objectToXml(newsMessage);
                break;
            case "报名":
                //获得用户授权，拉取用户信息，存入微信号昵称对应表
                message = createSignUpRedirectUri(map);
                break;
            case "海报":
                message = createPoster(map);
                break;
            case "排行榜":
                // 点击 排行榜 查看
                message = getRankingLink(map);
                break;
            default:
                // 1. 封装对象
                TextMessage textMessage = TextMessage.getAntonym(map);
                // 2. 序列化对象
                message = XmlUtils.objectToXml(textMessage);
                break;
        }
        return message;
    }

    private String getRankingLink(Map<String, Object> map) {
        String url = "http://" + redirectDomain + "/getRankingList";
        map.put("Content", "点击查看：<a style='color:#007ecc;' href=\"" + url + "\">助力排行榜</a>");
        TextMessage textMessage = TextMessage.getReplyTextMessage(map);
        return XmlUtils.objectToXml(textMessage);
    }

    private String createPoster(Map<String, Object> map) {

        String url = "https://api.weixin.qq.com/cgi-bin/qrcode/create" + HttpUtils.getQueryString(new HashMap<String, Object>(){{
            this.put("access_token", TokenUtils.getToken(appId, secret));
        }});
        //String data = "{\"action_name\": \"QR_LIMIT_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": \"oRQ325lwAb_WyRRs0WsY3g3i6RME\"}}}";
        //封装二维码参数
        QRCode qrCode = new QRCode();
        qrCode.setAction_name(QRCodeConstant.ACTION_NAME);
        String fromUserName = (String) map.get("FromUserName");
        qrCode.setAction_info(new ActionInfo(new Scene(fromUserName)));
        // 构造json
        String json = JsonUtils.objectToJson(qrCode);
        // 发送请求
        String result = HttpUtils.doPost(url, json);
        // 保存到本地
        String qrPath = getQRCodeImage(result, fromUserName);
        // 合成图片
        // 获取用户图像：FormUserName
        TUser user = userMapper.selectByPrimaryKey(fromUserName);
        String mergeImgPath = "";
        try {
            System.out.println(qrPath);
            System.out.println(user.getHeadimgurl());
            System.out.println(fromUserName);
            mergeImgPath = ImageUtils.MergeImage(qrPath, user.getHeadimgurl(), fromUserName);
        } catch (Exception e) {
            e.printStackTrace();
        }
        // 上传合成的图片到微信服务器
        String mediaId = uploadQRCodeImage(mergeImgPath);
        // 合成图片资源返回
        ImageMessage imageMessage = ImageMessage.getImageMessage(map, mediaId);
        return XmlUtils.objectToXml(imageMessage);
    }

    private String uploadQRCodeImage(String mergeImgPath) {
        return MediaMessage.sendImage(mergeImgPath, appId, secret);
    }

    /**
     * 保存二维码至本地
     * @param result
     * @param fromUserName
     * @return 图片本地保存的路径
     */
    private String getQRCodeImage(String result, String fromUserName) {
        String ticket = (String) JsonUtils.jsonToMap(result).get("ticket");
        String ticketUrl = String.format("https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=%s", ticket);
        String path = HttpUtils.download(ticketUrl, fromUserName);
        return path;
    }

    /*
        引导裂变用户访问地址进行授权，之后改用模版消息来封装
    */
    private String createSignUpRedirectUri(Map<String, Object> map) {
        System.out.println("http://" + redirectDomain + "/getSignUpUserInfo");
        //获得关注者的信息（微信号、昵称、头像等）并存入微信号昵称对应表
        //先引导用户访问地址进行授权，之后改用模版消息来封装、
        String url = "https://open.weixin.qq.com/connect/oauth2/authorize" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
            this.put("appid", appId);
            this.put("redirect_uri", "http://" + redirectDomain + "/getSignUpUserInfo");
            this.put("scope", "snsapi_userinfo");
        }}) + "#wechat_redirect";
//      + "#wechat_redirect";
        map.put("Content", "点击链接：<a href=\"" + url + "\">参与活动</a>");
        TextMessage textMessage = TextMessage.getReplyTextMessage(map);
        return XmlUtils.objectToXml(textMessage);
    }

    private String handleEvent(Map<String, Object> map) {
        String message = "";
        // 获取event值
        String event = (String) map.get("Event");
        // 事件分支
        switch (event) {
            case "CLICK":
                message = EventUtils.handleClick(map);
                break;
            case "VIEW":
                System.out.println("view");
                break;
            case "SCAN":
                message = EventUtils.handleScan(map);
                break;
            case "subscribe":
                message = handleSubscribeEvent(map);
                break;
            default:
                break;
        }
        return message;
    }

    /**
     * 获得分享者的微信号
     * @param eventKey
     * @return
     */
    private String getSharedUserWxId(String eventKey) {
        return eventKey.substring(eventKey.indexOf('_') + 1);
    }
    private String handleSubscribeEvent(Map<String, Object> map) {
        String message = "";
        String sharedUserWxId = getSharedUserWxId((String) map.get("EventKey"));
        if(StringUtils.hasLength(sharedUserWxId)) {
            TFollowInfo tFollowInfo = EventUtils.handleSubscribeByKey(map, sharedUserWxId);
            followInfoMapper.insertSelective(tFollowInfo);
            //查询当前助力值和档次信息
            int count = followInfoMapper.selectCountByOpenid(sharedUserWxId);
            List<TAssistLevel> assistLevels = assistLevelMapper.selectAll();
            // 给分享者推送消息，发送模版消息
            TextModelMessage.sendModelMessage(sharedUserWxId, count, assistLevels, appId, secret);
            //获取用户信息，这一步可以不用获取，待用户报名活动时再获取
            //用户关注后的回复内容，点击链接->回复"海报"，生成海报
            String url = "https://open.weixin.qq.com/connect/oauth2/authorize" + HttpUtils.getQueryString(new HashMap<String, Object>() {{
                this.put("appid", appId);
                this.put("redirect_uri", "http://" + redirectDomain + "/getSignUpUserInfo");
                this.put("response_type", "code");
                this.put("scope", "snsapi_userinfo");
            }}) + "#wechat_redirect";
            String content = "欢迎关注本公众号，我们举办了\"开源时代，共码未来\"活动，分享活动海报邀请好友扫码进行助力，" +
                    "助力人数满足条件可领取精美大礼包一份：键盘+鼠标+Java全套学习资料！" +
                    "点击链接：<a style='color:#007ecc;' href=\"" + url + "\">参与活动</a>";
            map.put("Content", content);
            TextMessage textMessage = TextMessage.getReplyTextMessage(map);
            message = XmlUtils.objectToXml(textMessage);
        }else {
            message = EventUtils.handleSubscribe(map);
        }
        return message;
    }
}
